package com.dai.rpc.netty.handler;

import com.dai.rpc.constant.MessageTypeEnum;
import com.dai.rpc.constant.MyRpcConstants;
import com.dai.rpc.exceptions.MyRpcException;
import com.dai.rpc.factory.SingletonFactory;
import com.dai.rpc.message.RpcMessage;
import com.dai.rpc.message.RpcRequest;
import com.dai.rpc.message.RpcResponse;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class MyNettyServerHandler extends ChannelInboundHandlerAdapter {

    private MyRequestHandler myRequestHandler;

    public MyNettyServerHandler() {
        this.myRequestHandler = SingletonFactory.getInstance(MyRequestHandler.class);
    }

    /**
     * 编解码之后的消息经由处理器处理
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        // 服务端接收消息
        // 接收客户端发来的数据，数据肯定包括要调用的服务提供者的接口和方法
        // 解析消息，去找到对应的服务提供者，然后调用得到结果，发消息给客户端即可
        /*try {
            if (msg instanceof RpcMessage) {
                // 如果接收到的消息是RpcMessage，那么进行处理
                RpcMessage message = (RpcMessage) msg;
                byte messageType = message.getMessageType();
                if (MessageTypeEnum.REQUEST.getCode() == messageType) {
                    // 如果是请求消息，那么请求调用服务获取结果并返回
                    RpcRequest data = (RpcRequest) message.getData();
                    Object result = myRequestHandler.handler(data);
                    // 装入结果
                    if (ctx.channel().isActive() && ctx.channel().isWritable()) {
                        RpcResponse success = RpcResponse.success(result, data.getRequestId());
                        message.setData(success);
                    } else {
                        RpcResponse<Object> response = RpcResponse.fail("net fail");
                        message.setData(response);
                    }
                }
                //log.info("服务端收到数据，并处理完成：" + message);
                // 把处理结果发送给客户端
                ctx.writeAndFlush(message).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
            }
        }catch (Exception e){
            e.printStackTrace();
            throw new MyRpcException("数据格式异常...");
        }finally {
            // netty自带的包进行释放
            ReferenceCountUtil.release(msg);
        }*/
        try {
            if (msg instanceof RpcMessage){
                // 拿到请求数据 ，调用对应服务提供方方法 获取结果 给客户端返回
                RpcMessage msMessage = (RpcMessage) msg;
                byte messageType = msMessage.getMessageType();
                if(MessageTypeEnum.HEARTBEAT_PING.getCode() == messageType){
                    // 接收到心跳包
                    msMessage.setMessageType(MessageTypeEnum.HEARTBEAT_PONG.getCode());
                    msMessage.setData(MyRpcConstants.RPC_PONG);
                }

                if (MessageTypeEnum.REQUEST.getCode() == messageType){
                    RpcRequest msRequest = (RpcRequest) msMessage.getData();
                    //处理业务，使用反射找到方法 发起调用 获取结果
                    Object result = myRequestHandler.handler(msRequest);
                    msMessage.setMessageType(MessageTypeEnum.RESPONSE.getCode());
                    if (ctx.channel().isActive() && ctx.channel().isWritable()) {
                        RpcResponse<Object> msResponse = RpcResponse.success(result, msRequest.getRequestId());
                        msMessage.setData(msResponse);
                    }else{
                        msMessage.setData(RpcResponse.fail("net fail"));
                    }
                }
                log.info("服务端接收到消息，并发送响应消息：{}",msMessage);
                ctx.writeAndFlush(msMessage).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
            }
        }catch (Exception e){
            e.printStackTrace();
            throw new MyRpcException("数据格式异常...");
        }finally {
            // netty自带的包进行释放
            ReferenceCountUtil.release(msg);
        }

    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {

        // 处理心跳检测
        if(evt instanceof IdleStateEvent){
            IdleState state = ((IdleStateEvent) evt).state();
            if(state == IdleState.READER_IDLE){
                log.info("客户端10s，未发送请求数据，通道关闭");
                ctx.close();
            }
        }else{
            super.userEventTriggered(ctx, evt);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
        ctx.close();
    }
}
